/* eslint-disable no-console */
// noinspection JSUnusedGlobalSymbols,ES6PreferShortImport

/* =============================== 日志类 =============================== */
import { getCurrentURL, PROJECT_PREFIX } from '../types/constants'
import { SYMBOLS } from '../types/interfaces/symbols'
import { ConfigUtils } from './utils/base/config'
import { ToolKit } from './utils/toolkit'

export interface LogClearStrategy {
  type: 'on-page-load' | 'time-based' | 'never'
  description?: string
  days?: number // 仅time-based策略需要
}

export enum LogLevel {
  debug = 'debug',
  info = 'info',
  warn = 'warn',
  error = 'error',
}

interface LogConfig {
  level: LogLevel
  enabled: boolean
  includeCaller?: boolean // 是否包含调用者信息
  maxCacheSize?: number // 可选：最大缓存日志数量
  maxStorageSize?: number // 可选：最大存储大小（MB）
  clearStrategy?: LogClearStrategy // 清空策略配置
}

// 默认策略
const DEFAULT_CLEAR_STRATEGY: LogClearStrategy = {
  type: 'on-page-load',
  description: '每次访问页面时自动清空当前页面的日志',
}

export interface LogEntry {
  id?: number // IndexedDB 自动生成的ID
  url: string
  timestamp: string
  level: string
  message: string
  stack?: string
  data?: any[]
  error?: {
    name: string
    message: string
    stack?: string
  }
}

const DEFAULT_LOG_CALLER_INFO: LogCallerInfo = {
  functionName: 'anonymous',
  fileName: 'unknown',
  lineNumber: '0',
}

interface LogCallerInfo {
  functionName: string
  fileName: string
  lineNumber: string
}

// 分组信息接口
interface LogGroupInfo {
  id: symbol
  name: string
  startTime: number
  options: LogGroupOptions
}

// 分组选项
interface LogGroupOptions {
  collapsed?: boolean
  color?: string
  successMessage?: string
  errorMessage?: string
  enableMessage?: boolean
  enableTiming?: boolean
}
// 日志回调函数类型
type LogFunction = (msg: string, type?: LogStyle) => void
// 异步操作函数类型
type LogAsyncOperation<T> = (log: LogFunction) => Promise<T>
// 同步操作函数类型
type LogSyncOperation<T> = (log: LogFunction) => T
// 通用操作函数类型
type LogOperation<T> = (log: LogFunction) => T | Promise<T>

// 计时器信息
interface LogTimerInfo {
  startTime: number
  label: string
  active: boolean
}

export enum LogStyle {
  debug = 'debug',
  info = 'info',
  notice = 'notice',
  warn = 'warn',
  error = 'error',
  success = 'success',
  important = 'important',
  attention = 'attention',
  hint = 'hint',
  tip = 'tip',
  mark = 'mark',
  groupHeader = 'groupHeader',
  groupHeaderCollapsed = 'groupHeaderCollapsed',
  timer = 'timer',
  counter = 'counter',
}

export enum ClassicLogColor {
  //  柔和的深色系（适合日志）
  darkGray = '#2D3748', // 深灰
  charcoal = '#4A5568', // 炭灰
  slate = '#718096', // 石板灰
  gray = '#A0AEC0', // 中灰

  // 柔和的彩色系（区分级别但不刺眼）
  mutedRed = '#C53030', // 柔和红（错误）
  mutedOrange = '#DD6B20', // 柔和橙（警告）
  mutedGreen = '#38A169', // 柔和绿（成功）
  mutedBlue = '#3182CE', // 柔和蓝（信息）
  mutedPurple = '#805AD5', // 柔和紫（调试）
  mutedTeal = '#319795', // 柔和青（详细信息）

  // 专属颜色
  mutedAmber = '#D97706', // 琥珀色（tip - 实用技巧）
  mutedIndigo = '#4F46E5', // 靛蓝色（hint - 智能提示）
  mutedRose = '#E11D48', // 玫瑰色
  mutedEmerald = '#059669', // 翡翠绿

  // 中性色
  brown = '#8B4513', // 棕色
  olive = '#808000', // 橄榄绿
  navy = '#000080', // 海军蓝
  maroon = '#800000', // 栗色

  white = '#FFFFFF', // 白色
}

export enum NeonColor {
  // 🔥 带有发光效果的颜色
  glowRed = '#FF006E', // 发光红
  glowOrange = '#FF9E00', // 发光橙
  glowYellow = '#FFEE00', // 发光黄
  glowGreen = '#00FF88', // 发光绿
  glowBlue = '#00B4D8', // 发光蓝
  glowPurple = '#9D4EDD', // 发光紫

  // ✨ 超亮霓虹色
  ultraViolet = '#A020F0', // 紫外线紫
  electricViolet = '#8F00FF', // 电光紫
  neonCyan = '#00F5FF', // 霓虹青
  acidGreen = '#B0FF00', // 酸性绿
}

export function getLogColorStyle(color: string): string {
  return `
    padding: 2px 4px;
    border-radius: 3px;
    color: ${color};
    font-weight: 600;
    `
}

export class Logger {
  readonly id: string = 'logger'
  readonly name: string = 'Logger'
  config: LogConfig
  private loggerMethodNames: string[]
  private prefix: string = ''
  private dbName: string = `${PROJECT_PREFIX}-logger`
  private storeName: string = 'logs'
  private dbVersion: number = 1
  private readonly dbPromise: Promise<IDBDatabase>
  private cache: LogEntry[] = [] // 内存中的临时缓存
  // 白名单
  private noStoreMessages = []
  private styles: Record<LogStyle, string> = {
    // 基础日志级别
    debug: getLogColorStyle(ClassicLogColor.mutedPurple),
    info: getLogColorStyle(ClassicLogColor.slate),
    warn: getLogColorStyle(ClassicLogColor.mutedOrange),
    error: getLogColorStyle(ClassicLogColor.mutedRed),

    // 业务样式
    success: getLogColorStyle(NeonColor.glowGreen),
    important: getLogColorStyle(NeonColor.glowBlue),
    attention: `
      padding: 3px 6px;
      background: linear-gradient(90deg, #D84315, #E64A19, #FF5722);
      border-radius: 4px;
      color: #FFFFFF;
      font-weight: 700;
      text-shadow: 0 1px 1px rgba(0,0,0,0.3);
    `,
    notice: `
      ${getLogColorStyle(NeonColor.glowYellow)}
      background: linear-gradient(135deg, rgba(255, 238, 0, 0.15), rgba(255, 215, 0, 0.1));
      border-left: 3px solid rgba(255, 238, 0, 0.5);
      `,
    hint: getLogColorStyle(ClassicLogColor.olive),
    tip: getLogColorStyle(ClassicLogColor.mutedTeal),
    mark: getLogColorStyle(NeonColor.glowPurple),

    // 功能样式
    // 分组器
    groupHeader: `
      margin: 2px 0;
      padding: 6px 12px;
      background: rgba(0, 0, 0, 0.8);
      border: 1px solid #0FF;
      color: #0FF;
      font-family: 'Courier New', monospace;
      font-weight: 600;
      text-shadow: 0 0 10px #0FF, 0 0 20px #0FF, 0 0 30px #0FF;
      `,
    groupHeaderCollapsed: `
      padding: 2px 6px;
      border-left: 3px solid #6B7280;
      color: #6B7280;
      font-weight: 600;
      `,
    // 计时器
    timer: `
      color: #3B82F6;
      font-weight: 600;
      `,
    // 计数器
    counter: `
      color: #F59E0B;
      font-weight: 600;
      `,
  }

  // 多种堆栈格式模式
  private readonly STACK_PATTERNS: RegExp[] = [
    // 格式1: at functionName (file:line:column) - Chrome/Firefox
    /at\s+([^\s(]+)\s*\(([^)]+):(\d+):(\d+)\)/,
    // 格式2: at file:line:column - 简化格式
    /at\s+([^\s:]+)\s*:(\d+):(\d+)/,
    // 格式3: 匿名函数调用
    /at\s+<anonymous>:(\d+):(\d+)/,
  ]

  private groups: Map<symbol, LogGroupInfo> = new Map()
  private timers: Map<string, LogTimerInfo> = new Map()
  private counters: Map<string, number> = new Map()

  /**
   * 构造函数
   * @param config 日志配置
   */
  constructor(config?: LogConfig) {
    const defaultConfig = {
      level: LogLevel.info,
      enabled: true,
      maxStorageSize: 100, // 默认 100 MB
    }

    this.config = ConfigUtils.mergeConfig(
      defaultConfig,
      config || {},
    )

    // 收集所有方法名
    this.loggerMethodNames = ToolKit.func.getClassMethodNames(this)

    this.dbPromise = this.initDB()
    this.setupStrategy()
  }

  /**
   * 初始化 IndexedDB
   */
  private initDB(): Promise<IDBDatabase> {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open(this.dbName, this.dbVersion)

      request.onupgradeneeded = (event) => {
        const db = (event.target as IDBOpenDBRequest).result
        if (!db.objectStoreNames.contains(this.storeName)) {
          const store = db.createObjectStore(this.storeName, {
            keyPath: 'id',
            autoIncrement: true,
          })
          // 创建索引以便查询
          store.createIndex('level', 'level', { unique: false })
          store.createIndex('timestamp', 'timestamp', { unique: false })
          store.createIndex('url', 'url', { unique: false })
        }
      }

      request.onsuccess = (event) => {
        resolve((event.target as IDBOpenDBRequest).result)
      }

      request.onerror = (event) => {
        console.error('IndexedDB open error:', (event.target as IDBRequest).error)
        reject((event.target as IDBRequest).error)
      }
    })
  }

  /**
   * 添加日志到 IndexedDB
   */
  private async addToDB(entry: LogEntry): Promise<void> {
    try {
      // 检查是否包含不需要存储的消息
      if (this.noStoreMessages.some(msg => entry.message.includes(msg))) {
        return
      }

      const db = await this.dbPromise
      const transaction = db.transaction(this.storeName, 'readwrite')
      const store = transaction.objectStore(this.storeName)

      return new Promise((resolve, reject) => {
        const request = store.add(entry)

        request.onsuccess = () => {
          // 检查存储大小
          this.checkStorageSize().then(resolve).catch(reject)
        }

        request.onerror = (event) => {
          reject((event.target as IDBRequest).error)
        }
      })
    }
    catch (e) {
      console.error('Failed to add log to DB:', e)
      // 失败时保留在内存缓存
      this.cache.push(entry)
    }
  }

  /**
   * 检查并维护存储大小
   */
  private async checkStorageSize(): Promise<void> {
    try {
      const db = await this.dbPromise
      const size = await this.estimateDBSize(db)

      // 转换为MB
      const sizeMB = size / (1024 * 1024)

      if (sizeMB > (this.config.maxStorageSize || 100)) {
        // 超过限制，删除旧的日志
        await this.cleanupOldLogs()
      }
    }
    catch (e) {
      console.error('Failed to check storage size:', e)
    }
  }

  /**
   * 估算数据库大小
   */
  private async estimateDBSize(db: IDBDatabase): Promise<number> {
    return new Promise((resolve) => {
      let size = 0
      const transaction = db.transaction(this.storeName, 'readonly')
      const store = transaction.objectStore(this.storeName)
      const request = store.openCursor()

      request.onsuccess = (event) => {
        const cursor = (event.target as IDBRequest).result
        if (cursor) {
          // 粗略估算每条日志约1KB
          size += 1024
          cursor.continue()
        }
        else {
          resolve(size)
        }
      }

      request.onerror = () => {
        resolve(0)
      }
    })
  }

  /**
   * 清理旧日志
   */
  private async cleanupOldLogs(): Promise<void> {
    try {
      const db = await this.dbPromise
      const transaction = db.transaction(this.storeName, 'readwrite')
      const store = transaction.objectStore(this.storeName)
      const index = store.index('timestamp')

      // 获取最早的100条日志
      const request = index.openCursor(null, 'next')
      const logsToDelete: IDBValidKey[] = []

      return new Promise((resolve, reject) => {
        request.onsuccess = (event) => {
          const cursor = (event.target as IDBRequest).result
          if (cursor && logsToDelete.length < 100) {
            logsToDelete.push(cursor.primaryKey)
            cursor.continue()
          }
          else {
            // 删除选中的旧日志
            logsToDelete.forEach((key) => {
              store.delete(key)
            })
            resolve()
          }
        }

        request.onerror = (event) => {
          reject((event.target as IDBRequest).error)
        }
      })
    }
    catch (e) {
      console.error('Failed to cleanup old logs:', e)
    }
  }

  /**
   * 设置清理策略
   */
  private setupStrategy(): void {
    switch (this.config.clearStrategy?.type) {
      case 'time-based':
        // 添加 async IIFE 来处理异步调用
        (async () => {
          try {
            await this.setupTimeBasedClear()
          }
          catch (e) {
            console.error('Failed to setup time-based clear:', e)
          }
        })()
        break
      case 'never':
        // 不需要任何清理设置
        break
      case 'on-page-load':
      default:
        this.setupAutoClear()
        break
    }
  }

  /**
   * 设置基于时间的清理策略
   */
  private async setupTimeBasedClear(): Promise<void> {
    const checkAndClear = async () => {
      try {
        const db = await this.dbPromise
        const transaction = db.transaction(this.storeName, 'readonly')
        const store = transaction.objectStore(this.storeName)
        const index = store.index('timestamp')

        // 获取最新的日志（按时间降序获取第一条）
        const newestLog = await new Promise<LogEntry | null>((resolve) => {
          const request = index.openCursor(null, 'prev') // 注意这里是 'prev' 不是 'next'
          request.onsuccess = (e) => {
            resolve((e.target as IDBRequest<IDBCursorWithValue>).result?.value || null)
          }
          request.onerror = () => resolve(null)
        })

        if (newestLog) {
          const newestDate = new Date(newestLog.timestamp)
          const days = this.config.clearStrategy?.days || 7
          const thresholdDate = new Date()
          thresholdDate.setDate(thresholdDate.getDate() - days)

          // 如果最新日志早于阈值日期，说明所有日志都过期了
          if (newestDate < thresholdDate) {
            await this.clearCache()
          }
          else {
            // 否则只清理早于阈值日期的日志
            await this.clearLogsBefore(thresholdDate)
          }
        }
      }
      catch (e) {
        console.error('Time-based clear check failed:', e)
      }
    }

    // 立即执行一次检查
    await checkAndClear()

    // 每天检查一次
    setInterval(checkAndClear, 5 * 60 * 1000)
  }

  /**
   * 清理指定日期之前的日志
   */
  private async clearLogsBefore(date: Date, url?: string): Promise<void> {
    try {
      const db = await this.dbPromise
      const transaction = db.transaction(this.storeName, 'readwrite')
      const store = transaction.objectStore(this.storeName)
      const index = store.index('timestamp')
      // 创建复合范围：时间+URL
      const range = url
        ? IDBKeyRange.bound(
            [url, 0],
            [url, date.getTime()],
            false,
            true,
          )
        : IDBKeyRange.upperBound(date)

      return new Promise((resolve) => {
        const request = index.openCursor(range)

        request.onsuccess = (e) => {
          const cursor = (e.target as IDBRequest<IDBCursorWithValue>).result
          if (cursor) {
            cursor.delete() // 删除这条过期日志
            cursor.continue() // 继续处理下一条
          }
          else {
            resolve() // 没有更多数据了
          }
        }

        request.onerror = () => resolve()
      })
    }
    catch (e) {
      console.error('Failed to clear logs before date:', date, e)
    }
  }

  /**
   * 设置页面刷新时自动清空内存缓存
   */
  private setupAutoClear(): void {
    window.addEventListener('beforeunload', async () => {
      await this.clearCurrentUrlCache()
    })
  }

  /**
   * 获取缓存的日志
   * @param level 日志级别（可选）
   * @param limit 返回条数限制（可选，0或不传表示不限制）
   * @param reverse 是否反转顺序获取最新日志（默认为true）
   * @param url 按URL过滤日志
   */
  async getCachedLogs(
    level?: string,
    limit: number = 0,
    reverse: boolean = true,
    url?: string,
  ): Promise<LogEntry[]> {
    try {
      const db = await this.dbPromise
      const transaction = db.transaction(this.storeName, 'readonly')
      const store = transaction.objectStore(this.storeName)

      return new Promise((resolve) => {
        // 创建复合查询条件
        const keyRange = url
          ? IDBKeyRange.only(url)
          : null

        // 基础查询
        const request = level
          ? store.index('level').openCursor(keyRange, reverse ? 'prev' : 'next')
          : store.openCursor(keyRange, reverse ? 'prev' : 'next')

        const results: LogEntry[] = []

        request.onsuccess = (event) => {
          const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result
          if (cursor) {
            // 如果指定了URL，需要额外过滤
            if (!url || cursor.value.url === url) {
              results.push(cursor.value)
            }

            // 检查是否达到限制
            if (limit > 0 && results.length >= limit) {
              return resolve(results)
            }
            cursor.continue()
          }
          else {
            // 没有更多数据了
            resolve(results)
          }
        }

        request.onerror = () => {
          console.error('Failed to fetch logs from IndexedDB')
          resolve([])
        }
      })
    }
    catch (e) {
      console.error('Failed to get logs from DB:', e)
      return [...this.cache].filter(log => !url || log.url === url) // 返回内存中的缓存
    }
  }

  /**
   * 获取当前设置的清理策略描述
   */
  getClearStrategyDescription(): string {
    const strategy = this.config.clearStrategy || DEFAULT_CLEAR_STRATEGY
    let desc = `清空策略: ${strategy.type}${strategy.description ? `（${strategy.description}）` : ''}`

    if (strategy.type === 'time-based' && strategy.days) {
      desc += `（保留当前页面最近${strategy.days}天日志）`
    }

    return desc
  }

  /**
   * 清空日志
   */
  async clearCache(): Promise<void> {
    try {
      const db = await this.dbPromise
      const transaction = db.transaction(this.storeName, 'readwrite')
      const store = transaction.objectStore(this.storeName)

      return new Promise((resolve) => {
        const request = store.clear()

        request.onsuccess = () => {
          this.cache = []
          resolve()
        }

        request.onerror = () => {
          this.cache = []
          resolve()
        }
      })
    }
    catch (e) {
      console.error('Failed to clear logs:', e)
      this.cache = []
    }
  }

  /**
   * 清空当前URL的日志（选择性清除）
   */
  async clearCurrentUrlCache(): Promise<void> {
    const currentUrl = getCurrentURL() || '未知'

    try {
      // 1. 清空IndexedDB中当前URL的日志
      const db = await this.dbPromise
      const transaction = db.transaction(this.storeName, 'readwrite')
      const store = transaction.objectStore(this.storeName)
      const index = store.index('url')

      await new Promise<void>((resolve) => {
        const request = index.openCursor(IDBKeyRange.only(currentUrl))

        request.onsuccess = (e) => {
          const cursor = (e.target as IDBRequest<IDBCursorWithValue>).result
          if (cursor) {
            cursor.delete() // 删除当前URL的日志
            cursor.continue() // 继续处理下一条
          }
          else {
            resolve() // 所有当前URL日志已删除
          }
        }

        request.onerror = () => resolve()
      })

      // 2. 清空内存缓存（全清）
      this.cache = []
    }
    catch (e) {
      console.error('Failed to clear current URL logs:', e)
      // 出错时也清空内存缓存
      this.cache = []
    }
  }

  /**
   * 格式化错误对象
   */
  private formatError(error?: Error): {
    name: string
    message: string
    stack?: string
  } | undefined {
    if (!error)
      return undefined
    return {
      name: error.name,
      message: error.message,
      stack: error.stack,
    }
  }

  /**
   * 创建日志条目
   */
  private createLogEntry(
    level: string,
    message: string,
    data?: any[],
    error?: Error,
  ): LogEntry {
    return {
      timestamp: new Date().toLocaleString(),
      url: getCurrentURL() || '未知',
      level,
      message: this.prefix ? `[${this.prefix}] ${message}` : message,
      // eslint-disable-next-line unicorn/error-message
      stack: new Error().stack?.split('\n')[3]?.trim(),
      data,
      error: this.formatError(error),
    }
  }

  /**
   * 启用或禁用日志输出
   * @param value 启用状态
   */
  set enabled(value: boolean) {
    this.config.enabled = value
  }

  /**
   * 获取当前日志启用状态
   */
  get enabled(): boolean {
    return this.config.enabled
  }

  /**
   * 设置日志前缀
   * @param newPrefix 新的前缀
   */
  setPrefix(newPrefix: string): void {
    this.prefix = newPrefix
  }

  /**
   * 格式化日志消息
   * @param level 日志级别
   * @param message 日志消息
   * @param keep 是否保持原始消息
   */
  private formatMessage(level: LogLevel | 'impt' | 'succ' | 'mark', message: string, keep: boolean = false): string {
    if (keep)
      return message

    // 格式化时间
    const time = new Date().toLocaleTimeString('zh-CN', { hour12: false })

    let traceDetail = ''
    let formattedMessage = message

    if (this.config.includeCaller) {
      // 跟踪详情
      const traceInfo = this.generateTraceDetail(message)
      traceDetail = traceInfo.traceDetail
      formattedMessage = traceInfo.message
    }

    if (this.prefix.length === 0) {
      return `%c[${time}] [${level.toUpperCase()}]${traceDetail} ${formattedMessage}`
    }
    else {
      return `%c[${time}] [${level.toUpperCase()}] [${this.prefix}]${traceDetail} ${formattedMessage}`
    }
  }

  /**
   * 判断是否应该输出日志
   * @param level 日志级别
   */
  private shouldLog(level: LogLevel): boolean {
    if (!this.config.enabled)
      return false

    const levels: LogLevel[] = [LogLevel.debug, LogLevel.info, LogLevel.warn, LogLevel.error]
    const currentLevel = levels.indexOf(level)
    const configLevel = levels.indexOf(this.config.level)
    return currentLevel >= configLevel
  }

  /**
   * 输出调试日志（检查点）
   * @param message 日志消息
   * @param args 日志参数
   */
  checkpoint(message: string, ...args: any[]): void {
    if (this.shouldLog(LogLevel.debug)) {
      const content = this.formatMessage(LogLevel.info, message, true)
      console.debug(content, ...args)
    }
  }

  /**
   * 输出跟踪日志（检查点）
   * @param message 日志消息
   * @param args 日志参数
   */
  tracePoint(message: string | number, ...args: any[]): void {
    if (this.shouldLog(LogLevel.info)) {
      const content = this.formatMessage('mark', String(message))
      console.log(content, this.styles.mark)
      if (args.length > 0)
        console.log(...args)
    }
  }

  /**
   * 输出简洁信息日志（无样式简化版）
   * @param message 日志消息
   * @param args 日志参数
   */
  message(message: string, ...args: any[]): void {
    if (this.shouldLog(LogLevel.info)) {
      const content = this.formatMessage(LogLevel.info, message, true)
      console.log(content, ...args)
    }
  }

  /**
   * 输出成功日志
   * @param message 日志消息
   * @param args 日志参数
   */
  success(message: string, ...args: any[]): void {
    if (this.shouldLog(LogLevel.info)) {
      const content = this.formatMessage('succ', message)
      console.log(content, this.styles.success)
      if (args.length > 0)
        console.log(...args)
    }
  }

  /**
   * 输出重要日志
   * @param message 日志消息
   * @param args 日志参数
   */
  important(message: string, ...args: any[]): void {
    if (this.shouldLog(LogLevel.info)) {
      const content = this.formatMessage('impt', message)
      console.log(content, this.styles.important)
      if (args.length > 0)
        console.log(...args)
    }
  }

  /**
   * 输出注意日志
   * @param message 要高亮显示的消息
   * @param args 日志参数
   */
  attention(message: string, ...args: any[]): void {
    if (this.shouldLog(LogLevel.info)) {
      const content = this.formatMessage(LogLevel.info, message)
      console.log(content, this.styles.attention)
      if (args.length > 0)
        console.log(...args)
    }
  }

  /**
   * 输出开发者注意日志
   * @param message 日志消息
   * @param args 日志参数
   */
  notice(message: string, ...args: any[]): void {
    if (this.shouldLog(LogLevel.info)) {
      const content = this.formatMessage(LogLevel.info, message)
      console.log(content, this.styles.notice)
      if (args.length > 0)
        console.log(...args)
    }
  }

  /**
   * 输出提示日志（间接的、暗示性的，引导用户自己发现（温和、不强制），如：你可能想检查一下这个设置）
   * @param message 日志消息
   * @param args 日志参数
   */
  hint(message: string, ...args: any[]): void {
    if (this.shouldLog(LogLevel.info)) {
      const content = this.formatMessage(LogLevel.info, message)
      console.log(content, this.styles.hint)
      if (args.length > 0)
        console.log(...args)
    }
  }

  /**
   * 输出技巧日志（直接的、实用的，提供具体解决方案（积极、有帮助），如：试试这个快捷键：Ctrl+S）
   * @param message 日志消息
   * @param args 日志参数
   */
  tip(message: string, ...args: any[]): void {
    if (this.shouldLog(LogLevel.info)) {
      const content = this.formatMessage(LogLevel.info, message)
      console.log(content, this.styles.tip)
      if (args.length > 0)
        console.log(...args)
    }
  }

  /**
   * 输出添加操作日志（绿色 +）
   */
  added(message: string): void {
    this.message(` \u001B[1m\u001B[32m + \u001B[0m ${message}`)
  }

  /**
   * 输出移除操作日志（红色 -）
   */
  removed(message: string): void {
    this.message(` \u001B[1m\u001B[31m - \u001B[0m ${message}`)
  }

  /**
   * 输出更新/修改操作日志（黄色 *）
   */
  updated(message: string): void {
    this.message(` \u001B[1m\u001B[33m * \u001B[0m ${message}`)
  }

  /**
   * 打印应用信息
   * @param {string} name - 应用名称
   * @param {string} version - 应用版本
   */
  printAppInfo(
    name: string,
    version: string,
  ): void {
    const message = `%c ${name} %c V${version}`
    const defaultTextStyle = `
      margin: 5px 0; 
      padding: 4px 8px; 
      color: #fff; 
      font-weight: bold;
      font-size: 16px;
    `
    const nameStyle = `
      ${defaultTextStyle}
      border-radius: 3px 0 0 3px; 
      background: #3b82fe;
    `
    const versionStyle = `
      ${defaultTextStyle}
      border-radius: 0 3px 3px 0; 
      background: #FF6699;
    `
    this.message(message, nameStyle, versionStyle)
  }

  /**
   * 输出调试日志
   * @param message 日志消息
   * @param args 调试数据
   */
  debug(message: string, ...args: any[]): void {
    if (this.shouldLog(LogLevel.debug)) {
      const content = this.formatMessage(LogLevel.debug, message)
      console.debug(content, this.styles.debug)
      if (args.length > 0)
        console.debug(...args)
    }
  }

  /**
   * 输出信息日志
   * @param message 日志消息
   * @param args 日志参数
   */
  info(message: string, ...args: any[]): void {
    if (this.shouldLog(LogLevel.info)) {
      const content = this.formatMessage(LogLevel.info, message)
      console.log(content, this.styles.info)
      if (args.length > 0)
        console.log(...args)
    }
  }

  /**
   * 输出警告日志
   * @param message 日志消息
   * @param args 警告数据
   */
  warn(message: string, ...args: any[]): void {
    if (this.shouldLog(LogLevel.warn)) {
      const content = this.formatMessage(LogLevel.warn, message)
      console.log(content, this.styles.warn)
      if (args.length > 0)
        console.log(...args)

      this.addToDB(this.createLogEntry(LogLevel.warn, message, args))
        .catch(e => console.error('Failed to save error log:', e))
    }
  }

  /**
   * 输出错误日志
   * @param message 日志消息
   * @param error 错误对象
   * @param args 错误数据
   */
  error(message: string, error?: any, ...args: any[]): void {
    if (this.shouldLog(LogLevel.error)) {
      const content = this.formatMessage(LogLevel.error, message)
      console.log(content, this.styles.error)
      if (error)
        console.error(error)
      if (args.length > 0)
        console.log(...args)

      this.addToDB(this.createLogEntry(LogLevel.error, message, args, error))
        .catch(e => console.error('Failed to save error log:', e))
    }
  }

  /**
   * 输出表格日志
   * @param message 日志消息
   * @param data 表格数据
   */
  table(message: string, data: any[]): void {
    if (this.shouldLog(LogLevel.info)) {
      const empty = !data || data.length === 0
      const remark = empty ? '（无数据）' : ''

      const content = this.formatMessage(LogLevel.info, `${message}${remark}`)
      console.log(content, this.styles.info)

      if (empty)
        return

      console.table(data)
    }
  }

  /**
   * 生成跟踪详情
   */
  private generateTraceDetail(message: string): {
    traceDetail: string
    message: string
  } {
    const traceInfo = this.getCallerInfo()
    const className = this.extractClassName(message)

    const traceDetailParts: string[] = []

    if (className)
      traceDetailParts.push(className)

    if (traceInfo !== `${DEFAULT_LOG_CALLER_INFO.functionName}`)
      traceDetailParts.push(traceInfo)

    const traceDetail = traceDetailParts.join(':')

    return {
      traceDetail: traceDetail ? `[${traceDetail}]` : '',
      message: traceDetail && className ? message.replace(`[${className}]`, '').trim() : message.trim(),
    }
  }

  /**
   * 获取调用者信息
   * @returns 格式化的调用栈信息
   */
  private getCallerInfo(options?: {
    includeFileName: boolean
  }): string {
    const { includeFileName = false } = options || {}
    try {
      // 创建 Error 对象获取堆栈
      const stack = new Error('Stack trace generation').stack

      if (!stack)
        return ''

      const stackLines = stack.split('\n')

      // 跳过前几行（Error 对象创建、 中间日志函数、Logger 类）
      for (let i = 5; i < stackLines.length; i++) {
        const line = stackLines[i].trim()

        // 解析调用栈行，提取有用信息
        const callerInfo = this.parseStackLine(line)
        const { fileName, functionName } = callerInfo

        if (callerInfo) {
          const parts: string[] = []

          if (includeFileName)
            parts.push(`${fileName}@`)

          parts.push(`${functionName}`)
          return `${parts.join('')}`
        }
      }

      return ''
    }
    catch {
      // 避免因堆栈解析失败影响正常日志输出
      return ''
    }
  }

  /**
   * 解析堆栈行，提取简洁调用信息
   * @param line 堆栈行
   * @returns 格式化的调用信息
   */
  private parseStackLine(line: string): LogCallerInfo {
    try {
      for (const pattern of this.STACK_PATTERNS) {
        const match = line.match(pattern)

        if (match)
          return this.extractCallerInfo(match, pattern)
      }

      return DEFAULT_LOG_CALLER_INFO
    }
    catch {
      return DEFAULT_LOG_CALLER_INFO
    }
  }

  /**
   * 从匹配结果中提取调用者信息
   */
  private extractCallerInfo(match: RegExpMatchArray, pattern: RegExp): LogCallerInfo {
    let { functionName, fileName, lineNumber } = DEFAULT_LOG_CALLER_INFO
    let traceChain = ''

    // 根据不同的模式提取信息
    if (pattern === this.STACK_PATTERNS[0]) {
      // 格式1: at functionName (file:line:column)
      traceChain = match[1]
      functionName = this.sanitizeFunctionName(match[1])
      fileName = this.extractFileName(match[2])
      lineNumber = match[3]
    }
    else if (pattern === this.STACK_PATTERNS[1]) {
      // 格式2: at file:line:column
      traceChain = match[1]
      fileName = this.extractFileName(match[1])
      lineNumber = match[2]
      // 尝试从文件名中提取函数名
      functionName = this.extractFunctionFromUrl(fileName)
    }
    else if (pattern === this.STACK_PATTERNS[2]) {
      // 格式3: 匿名函数
      lineNumber = match[1]
      functionName = 'anonymous'
    }

    // 过滤掉日志类内部的方法
    if (this.isLoggerInternalCall(traceChain))
      return DEFAULT_LOG_CALLER_INFO

    return {
      functionName,
      fileName,
      lineNumber,
    }
  }

  /**
   * 从日志消息中提取类名
   */
  extractClassName(message: string): string {
    // noinspection RegExpRedundantEscape
    const classNameMatch = message.match(/\[([^\]]+)\]/)
    return classNameMatch?.[1] || ''
  }

  /**
   * 清理函数名
   */
  private sanitizeFunctionName(rawName: string): string {
    if (!rawName)
      return 'anonymous'

    // 移除对象方法前缀（如 er.level.）
    const name = rawName.trim()

    // 处理类似 "er.level.info" 这样的名称
    if (name.includes('.'))
      return this.extractMeaningfulFunctionName(name)

    // 处理压缩后的变量名
    if (this.isMinifiedVariableName(name))
      return 'func'

    return name || 'anonymous'
  }

  /**
   * 从点分隔的路径中提取有意义的函数名
   */
  private extractMeaningfulFunctionName(dotPath: string): string {
    const parts = dotPath.split('.')
    const lastPart = parts[parts.length - 1]
    const secondLastPart = parts.length >= 2 ? parts[parts.length - 2] : ''

    // 如果倒数第二部分不是压缩的变量名，直接使用
    if (secondLastPart && !this.isMinifiedVariableName(secondLastPart) && secondLastPart !== 'level')
      return secondLastPart

    // 如果最后一部分不是压缩的变量名，直接使用
    if (!this.isMinifiedVariableName(lastPart))
      return lastPart

    // 如果都是压缩的变量名，尝试找到第一个有意义的名称
    for (let i = parts.length - 1; i >= 0; i--) {
      if (!this.isMinifiedVariableName(parts[i])) {
        return parts[i]
      }
    }

    // 如果全部都是压缩的变量名，返回默认值
    return 'func'
  }

  /**
   * 判断是否是压缩后的变量名
   */
  private isMinifiedVariableName(name: string): boolean {
    if (!name || name.length === 0)
      return false

    // 单字符或双字符的小写字母
    if (name.length <= 2 && /^[a-z]+$/i.test(name))
      return true

    // 常见压缩变量名模式
    const minifiedPatterns = [
      /^[a-z]{1,2}$/i, // 单/双字符小写字母
      /^[a-z]\d+$/i, // 字母+数字 (a1, b2等)
      /^\$[a-z]$/i, // $加单字符 ($a, $b等)
      /^_[a-z]$/i, // 下划线加单字符 (_a, _b等)
      /^[a-z]_$/i, // 单字符加下划线 (a_, b_等)
    ]

    return minifiedPatterns.some(pattern => pattern.test(name))
  }

  /**
   * 提取简洁的文件名
   */
  private extractFileName(filePath: string): string {
    if (!filePath)
      return 'unknown'

    try {
      // 处理 Chrome 扩展 URL
      if (filePath.startsWith('chrome-extension://'))
        return this.parseChromeExtensionUrl(filePath)

      // 处理普通文件路径
      const fileName = filePath.split('/').pop() || filePath.split('\\').pop() || filePath

      // 移除查询参数和哈希
      return fileName.split('?')[0].split('#')[0]
    }
    catch {
      return 'unknown'
    }
  }

  /**
   * 解析 Chrome 扩展 URL
   */
  private parseChromeExtensionUrl(url: string): string {
    try {
      const urlObj = new URL(url)
      const pathname = urlObj.pathname

      // 提取文件名
      let fileName = pathname.split('/').pop() || 'extension'

      // 处理油猴脚本的特殊情况
      if (url.includes('userscript.html')) {
      // 从查询参数中提取脚本名
        const scriptName = urlObj.searchParams.get('name')
        if (scriptName) {
          try {
          // URL 解码脚本名
            const decodedName = decodeURIComponent(scriptName)
            // 移除扩展名，只保留脚本名
            fileName = decodedName.replace('.user.js', '')
          }
          catch {
            fileName = 'userscript'
          }
        }
        else {
          fileName = 'userscript'
        }
      }

      return fileName
    }
    catch {
      return 'chrome-extension'
    }
  }

  /**
   * 从 URL 中尝试提取函数名
   */
  private extractFunctionFromUrl(fileName: string): string {
    if (fileName.includes('userscript.html')) {
      return 'userscript'
    }
    return 'main'
  }

  /**
   * 检查是否是 Logger 类内部的调用
   */
  private isLoggerInternalCall(traceChain: string): boolean {
    return this.loggerMethodNames.some(methodName => traceChain.includes(`level.${methodName}`))
  }

  /* =============================== 分组器 =============================== */
  /**
   * 开始一个分组
   * @param name 分组名称
   * @param options 分组选项
   * @returns 分组 ID
   */
  startGroup(name: string, options: LogGroupOptions = {}): symbol {
    if (!this.shouldLog(LogLevel.info))
      return Symbol('disabled')

    const groupId = Symbol(name)
    const { collapsed = false, color } = options

    if (collapsed) {
      console.groupCollapsed(`%c${name}`, this.styles[color || LogStyle.groupHeaderCollapsed])
    }
    else {
      console.group(`%c${name}`, this.styles[color || LogStyle.groupHeader])
    }

    const groupInfo: LogGroupInfo = {
      id: groupId,
      name,
      startTime: performance.now(),
      options,
    }

    this.groups.set(groupId, groupInfo)
    return groupId
  }

  /**
   * 在分组内记录日志
   * @param groupId 分组 ID
   * @param message 日志消息
   * @param type 日志类型
   */
  groupLog(groupId: symbol, message: string, type: LogStyle = LogStyle.info): void {
    if (!this.shouldLog(LogLevel.info))
      return

    if (!this.groups.has(groupId)) {
      this.warn(`[${this.name}] 分组不存在: ${groupId.description}`)
      return
    }

    const group = this.groups.get(groupId)!
    const timeDiff = (performance.now() - group.startTime).toFixed(2)

    console.log(`%c[+${timeDiff}ms] ${message}`, this.styles[type] || this.styles.info)
  }

  /**
   * 结束分组
   * @param groupId 分组 ID
   * @param finalMessage 结束消息
   * @returns 分组持续时间（毫秒）
   */
  endGroup(groupId: symbol, finalMessage: string | null = null): number {
    if (!this.groups.has(groupId)) {
      this.warn(`[${this.name}] 分组不存在: ${groupId.description}`)
      return 0
    }

    const group = this.groups.get(groupId)!
    const duration = (performance.now() - group.startTime).toFixed(2)

    if (finalMessage)
      console.log(`%c ${SYMBOLS.STATUS.SUCCESS} ${finalMessage} (${duration}ms)`, this.styles.success)

    console.groupEnd()
    this.groups.delete(groupId)

    return Number.parseFloat(duration)
  }

  async executeWithLogging<T>(
    name: string,
    operation: LogAsyncOperation<T>,
    options?: LogGroupOptions,
  ): Promise<T>
  async executeWithLogging<T>(
    name: string,
    operation: LogSyncOperation<T>,
    options?: LogGroupOptions,
  ): Promise<T>
  async executeWithLogging<T>(
    name: string,
    operation: LogOperation<T>,
    options: LogGroupOptions,
  ): Promise<T> {
    const mergedOptions: LogGroupOptions = ToolKit.config.mergeConfig<LogGroupOptions>({
      collapsed: false,
      color: LogStyle.groupHeader,
      enableMessage: false,
      enableTiming: false,
    }, options)

    const { enableMessage, enableTiming, successMessage, errorMessage } = mergedOptions

    const groupId = this.startGroup(name, mergedOptions)
    const startTime = performance.now()

    try {
      // 记录开始执行
      if (enableMessage)
        this.groupLog(groupId, '开始执行...', LogStyle.info)

      // 执行操作并检测是否为异步
      const result = operation((msg, type = LogStyle.info) => {
        this.groupLog(groupId, msg, type)
      })

      // 检测是否为 Promise
      if (result instanceof Promise) {
        // 异步操作
        const asyncResult = await this.handleAsyncOperation(result, groupId, enableTiming!, startTime)
        this.endGroup(groupId, enableMessage ? successMessage || '异步操作成功' : null)
        return asyncResult
      }
      else {
        // 同步操作
        const syncResult = this.handleSyncOperation(result, groupId, enableTiming!, startTime)
        this.endGroup(groupId, enableMessage ? successMessage || '同步操作成功' : null)
        return syncResult
      }
    }
    catch (error) {
      // 统一的错误处理
      this.handleOperationError(error, groupId, enableTiming!, startTime)
      this.endGroup(groupId, enableMessage ? errorMessage || '操作失败' : null)
      throw error
    }
  }

  /**
   * 处理异步操作
   */
  private async handleAsyncOperation<T>(
    promise: Promise<T>,
    groupId: symbol,
    enableTiming: boolean,
    startTime: number,
  ): Promise<T> {
    try {
      const result = await promise
      const duration = enableTiming ? performance.now() - startTime : 0

      if (enableTiming) {
        this.groupLog(groupId, `异步操作完成 (${duration.toFixed(2)}ms)`, LogStyle.hint)
      }
      else {
        this.groupLog(groupId, '异步操作完成', LogStyle.hint)
      }

      return result
    }
    catch (error) {
      const duration = enableTiming ? performance.now() - startTime : 0
      this.groupLog(groupId, `异步操作失败 (${duration.toFixed(2)}ms)`, LogStyle.error)
      throw error
    }
  }

  /**
   * 处理同步操作
   */
  private handleSyncOperation<T>(
    result: T,
    groupId: symbol,
    enableTiming: boolean,
    startTime: number,
  ): T {
    const duration = enableTiming ? performance.now() - startTime : 0

    if (enableTiming) {
      this.groupLog(groupId, `同步操作完成 (${duration.toFixed(2)}ms)`, LogStyle.hint)
    }
    else {
      this.groupLog(groupId, '同步操作完成', LogStyle.hint)
    }

    return result
  }

  /**
   * 处理操作错误
   */
  private handleOperationError(
    error: unknown,
    groupId: symbol,
    enableTiming: boolean,
    startTime: number,
  ): void {
    const duration = enableTiming ? performance.now() - startTime : 0
    const errorMessage = error instanceof Error ? error.message : '未知错误'

    if (enableTiming) {
      this.groupLog(groupId, `操作失败: ${errorMessage} (${duration.toFixed(2)}ms)`, LogStyle.error)
    }
    else {
      this.groupLog(groupId, `操作失败: ${errorMessage}`, LogStyle.error)
    }
  }

  /**
   * 获取当前活跃的分组
   */
  getActiveGroups(): LogGroupInfo[] {
    return Array.from(this.groups.values())
  }

  /* =============================== 计时器 =============================== */
  /**
   * 开始计时器
   * @param label 计时器标签
   */
  time(label: string = 'default'): void {
    if (!this.shouldLog(LogLevel.info))
      return

    this.timers.set(label, {
      startTime: performance.now(),
      label,
      active: true,
    })

    console.log(`%c[TIMER] ${label}: 开始计时`, this.styles.timer)
  }

  /**
   * 结束计时器并输出耗时
   * @param label 计时器标签
   * @returns 耗时（毫秒）
   */
  timeEnd(label: string = 'default'): number {
    if (!this.shouldLog(LogLevel.info))
      return 0

    const timer = this.timers.get(label)
    if (!timer || !timer.active) {
      this.warn(`[${this.name}] 计时器不存在或未启动: ${label}`)
      return 0
    }

    const duration = performance.now() - timer.startTime
    timer.active = false

    console.log(`%c[TIMER] ${label}: ${duration.toFixed(2)}ms`, this.styles.timer)
    return duration
  }

  /**
   * 记录计时器当前值（不停止计时）
   * @param label 计时器标签
   * @param message 自定义消息
   * @returns 当前耗时（毫秒）
   */
  timeLog(label: string = 'default', message?: string): number {
    if (!this.shouldLog(LogLevel.info))
      return 0

    const timer = this.timers.get(label)
    if (!timer || !timer.active) {
      this.warn(`[${this.name}] 计时器不存在或未启动: ${label}`)
      return 0
    }

    const duration = performance.now() - timer.startTime
    const logMessage = message ? `${message}: ${duration.toFixed(2)}ms` : `${duration.toFixed(2)}ms`

    console.log(`%c[TIMER] ${label}: ${logMessage}`, this.styles.timer)
    return duration
  }

  /**
   * 获取计时器状态
   * @param label 计时器标签
   */
  getTimer(label: string): LogTimerInfo | undefined {
    return this.timers.get(label)
  }

  /**
   * 获取所有活跃的计时器
   */
  getActiveTimers(): LogTimerInfo[] {
    return Array.from(this.timers.values()).filter(timer => timer.active)
  }

  /* =============================== 计数器 =============================== */
  /**
   * 计数器 - 增加指定标签的计数
   * @param label 计数器标签
   */
  count(label: string = 'default'): void {
    if (!this.shouldLog(LogLevel.info))
      return

    const currentCount = (this.counters.get(label) || 0) + 1
    this.counters.set(label, currentCount)

    console.log(`%c[COUNT] ${label}: ${currentCount}`, this.styles.counter)
  }

  /**
   * 计数器 - 重置指定标签的计数
   * @param label 计数器标签
   */
  countReset(label: string = 'default'): void {
    if (!this.shouldLog(LogLevel.info))
      return

    this.counters.set(label, 0)
    console.log(`%c[COUNT] ${label}: 已重置`, this.styles.counter)
  }

  /**
   * 计数器 - 获取指定标签的当前计数
   * @param label 计数器标签
   */
  getCount(label: string = 'default'): number {
    return this.counters.get(label) || 0
  }

  /**
   * 计数器 - 获取所有计数器的状态
   */
  getCounters(): Map<string, number> {
    return new Map(this.counters)
  }
}
